package com.neusoft.di.entity.error;

import com.neusoft.di.entity.common.CommonResult;
import com.neusoft.di.entity.common.ResultCode;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;

/**
 * @author Lucas
 * date 2024/3/6 19:11
 * description WebFlux异常拦截
 */
//@Slf4j
//@Component
//@Order(-2)
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
                                          WebProperties properties,
                                          ApplicationContext applicationContext,
                                          ServerCodecConfigurer codecConfigurer) {
        super(errorAttributes, properties.getResources(), applicationContext);
        this.setMessageWriters(codecConfigurer.getWriters());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    @SuppressWarnings("all")
    private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        Throwable error = getError(request);
        if (error instanceof WebExchangeBindException bindExc) {
            String msg;
            if (bindExc.hasErrors()) {
                FieldError fieldError = bindExc.getFieldErrors().get(0);
                String field = fieldError.getField();
                String message = fieldError.getDefaultMessage();
                msg = "【" + field + "】校验失败！";
                if (message != null) {
                    msg = msg + "msg: " + message;
                }
            } else {
                msg = bindExc.getMessage();
            }
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(CommonResult.failed(msg));
        } else if (error instanceof ResponseStatusException statusException) {
            if (statusException.getStatusCode() == HttpStatus.NOT_FOUND) {
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .bodyValue(CommonResult.failed(ResultCode.THE_ACCESSED_PATH_DOES_NOT_EXIST));
            }
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(statusException.getReason()));
        } else if (error instanceof GlobalException exc) {
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(CommonResult.failed(exc.getMessage()));
        } else {
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(CommonResult.failed((error.getMessage())));
        }
    }
}